﻿namespace Cellfish.Toolbox.Facts.Tasks
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;

    using Cellfish.Toolbox.Tasks;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class WaitHandleExtensionsFacts
    {
        [TestMethod]
        public void Given_ManualResetEvent_When_waiting_as_task_Then_task_completes_everytime_waited()
        {
            var mre = new ManualResetEvent(false);
            var firstWait = mre.WaitAsync();
            Assert.IsFalse(firstWait.Wait(TimeSpan.Zero), "First task not should be completed before event set.");
            mre.Set();
            Assert.IsTrue(firstWait.Wait(TimeSpan.FromSeconds(5)), "First task should be completed after event set.");
            Assert.IsTrue(mre.WaitAsync(TimeSpan.Zero).Result, "Second wait should be completed immediatly.");
        }

        [TestMethod]
        public void Given_ManualResetEvent_When_waiting_as_task_with_timeout_and_event_is_never_set_Then_task_completes_with_false()
        {
            var mre = new ManualResetEvent(false);
            Assert.IsFalse(mre.WaitAsync(TimeSpan.Zero).Result);
        }

        [TestMethod]
        public void Given_AutoResetEvent_When_waiting_multiple_times_Then_only_one_task_completes_at_a_time()
        {
            var are = new AutoResetEvent(false);
            var tasks = new List<Task>(3);
            for (int i = 0; i < 3; i++)
            {
                tasks.Add(are.WaitAsync());
            }

            for (int i = tasks.Count - 1; i > 0; i--)
            {
                are.Set();
                Assert.IsTrue(Task.WhenAny(tasks).Wait(TimeSpan.FromSeconds(5)), "No task completed in time.");
                tasks = tasks.Where(t => !t.IsCompleted).ToList();
                Assert.AreEqual(i, tasks.Count, "Wrong number of tasks remaining.");
            }
        }
    }
}
